ggplot2(13)-其它图形

绘制矩阵图

数据集

1
2
3
4
5
6
7
8
> head(mtcars)
mpg cyl disp hp drat wt qsec vs am gear carb
Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4
Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4
Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1
Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1
Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2
Valiant 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1

计算相关矩阵

1
2
mcor <- cor(mtcars)
round(mcor,digits=2)

绘图

1
2
library(corrplot)
corrplot(mcor)

mark

绘制相关矩阵,例如颜色广场和黑色文本标签,并且上边的文本标签呈现45度,如下所示:

1
corrplot(mcor,method="shade",shade.col=NA,tl.col = "black",tl.srt=45)

mark

更改颜色

现在更改一下相关矩阵的颜色,如下所示:

1
2
3
4
5
6
7
col <- colorRampPalette(c("#BB4444","#EE9988","#FFFFFF","#77AADD","#4477AA"))
corrplot(mcor,method="shade",shade.col=NA,tl.col = "black",tl.srt=45,
col=col(200),addCoef.col = "black",order="AOE",cl.pos = "r")
# method="shade"表示是否添加阴影,如果不写,则矩阵的小方格中是圆形
# order="AOE"表示前两个特征向量的角排序,选项有AOE,FPC,hclust,矩阵排序的依据,分别为特征值、第一主成分,层次聚类
# cl.pos=r表示,右侧是颜色的标度示意图
# addCoef.col = "black"表示添加上相关系数,并且为黑色

mark

绘制函数曲线

绘制正态分布曲线

使用stat_function()函数,为了得到合适的x的范围,必须给ggplot()函数传递一个“哑”数据库,如下所示:

1
2
p <- ggplot(data.frame(x=c(-3,3)),aes(x=x))
p + stat_function(fun=dnorm)

mark

绘制t分布曲线

1
2
p <- ggplot(data.frame(x=c(-3,3)),aes(x=x))
p + stat_function(fun=dt, args=list(df=2))

额外的参数使用list()进行传递,传递给args。

mark

绘制自定义的函数

第一个参数必须是x轴的值,并且必须返回y值,在这个案例中,我们绘制一个S型函数,如下所示:

1
2
3
4
5
myfun <- function(xvar){
1/(1+exp(-xvar+10))
}
ggplot(data.frame(x=c(0,20)),aes(x=x)) + stat_function(fun=myfun)

mark

计算函数值是使用给出的x范围内的101个点,如果函数跳跃很大,画出来的图可能有一些支离破碎的线段,为了让曲线更加光滑,可以给stat_function()传递一个更大的n,例如stat_function(fun=myfun,n=200)

在函数曲线下添加阴影

根据你的曲线函数定义了一个新的函数,把x范围外对应的值替换为NA,操作如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
# 定义一个函数,在0<x<2时返回dnorm(x),其它的时候返回NA
dnorm_limit <- function(x){
y <- dnorm(x)
y[x < 0 | x>2] <- NA
return(y)
}
#ggplot()使用“哑”数据
p <- ggplot(data.frame(x=c(-3,3)),aes(x=x))
p+stat_function(fun=dnorm_limit,geom="area",fill="blue",alpha=0.2)+
stat_function(fun=dnorm)

mark

需要注意的是,给这个函数传入的是一个向量,而不是一个单独的值,如果这个函数每次只操作一个元素,那么使用一个if/else语句来根据x值确定返回值是更合理,但是那样做在这里却行不通,因为x是一个含有许多值的向量。

R中有第一类函数,我们可以写一个函数来返回一个闭包,也就是说, 我们可以编写一个能够编写函数的函数,这个函数允许你传递一个函数、一个最小值,一个最大值,定义域外对应的值域返回NA,如下所示:

1
2
3
4
5
6
7
limitRange <- function(fun, min, max){
function(x){
y <- fun()
y[x < min | x > max] <- NA
return(y)
}
}

现在我们可以调用这个函数来生成另外一个函数,这和之前使用的dnorm_list()函数的效果是一样,如下所示:

1
2
3
4
5
# 返回一个函数
dlimit <- limitRange(dnorm,0,2)
# 对0-2之间的数字返回相应的计算结果
dlimit(-2:4)

结果如下所示:

1
2
> dlimit(-2:4)
[1] NA NA 0.39894228 0.24197072 0.05399097 NA NA

现在使用limitRange()来生成函数,并传递给stat_function()

1
2
3
p + stat_function(fun=dnorm)+
stat_function(fun=limitRange(dnorm,0,2),
geom="area",fill="blue",alpha=0.2)

mark

limitRange()函数可以用来生成任何函数的“区间限制式”函数,不局限于dnorm()。从上图中,我们哦可以知道,阴影区域并没有和我们给出的边界值范围完全齐,这是因为ggplot2在固定区间上计算函数值时做了个数值近似,并且这些区间没有完全落在指定的范围上,但我们可以通过设置stat_function(n=200)以增加插点数量的方式来提升近似的效果。

绘制网络图

网络图要使用igrpha包,如下所示:

绘制一个有向图的边:

1
2
3
library(igraph)
gd <- graph(c(1,2, 2,3,2,4, 1, 4, 5, 5, 3, 6))
plot(gd)

mark

绘制一个无向图,没有标签,如下所示:

1
2
3
gu <- graph(c(1,2, 2,3,2,4, 1, 4, 5, 5, 3, 6),directed=FALSE)
# do not draw label
plot(gu, vertex.label=NA)

mark

在网络图中,节点的位置并不是由所给数据确定的,它们是随机放置的,如果要让得到的图更可读,可以在绘图之前设置随机数种子,比如,可以浓度不同的随机数种子,直到得到一个比较满意的结果:

1
2
set.seed(100)
plot(gu)

我们还可以采用Fruchterman-Reingold布局算法,该算法的主要思想是所有节点之间都有电磁斥力,但是连接节点的边像弹簧一样,会把相应的节点拉在一起。

也哦可以从数据框中直接生图,使用数据框的前两列,并且每一列确定两个节点相连,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
library(gcookbook)
head(madmen2)
# Name1 Name2
# 1 Abe Drexler Peggy Olson
# 2 Allison Don Draper
# 3 Arthur Case Betty Draper
# 4 Bellhop in Baltimore Sal Romano
# 5 Bethany Van Nuys Don Draper
# 6 Betty Draper Don Draper
g <- graph.data.frame(madmen2,directed = TRUE)#
#从数据集中生成图像
par(mar=c(0,0,0,0))
#移除多余的空白边
plot(g,layout=layout.fruchterman.reingold,
vertex.size=8,
edge.arrow.size=0.5,
vertex.label=NA)

mark

也可以从数据框生成无向图,madmen数据集中一行就可以表示一条边,因为对于无向图来说,方向是没有意义的,现在我们使用圆圈布局,如下所示:

1
2
3
4
5
6
7
8
9
10
11
head(madmen)
# Name1 Name2
# 1 Betty Draper Henry Francis
# 2 Betty Draper Random guy
# 3 Don Draper Allison
# 4 Don Draper Bethany Van Nuys
# 5 Don Draper Betty Draper
# 6 Don Draper Bobbie Barrett
g <- graph.data.frame(madmen,directed = TRUE)
par(mar=c(0,0,0,0))
plot(g, layout=layout.circle,vertex.size=8,vertex.label=NA)

mark

igraph的一个替代选择是Rgraphviz,该包是Graphviz的前端,它的优点是能更方便地处理标签,而且也更容易控布局,由Bioconductor系统库维护,常用于绘制KEGG图。

在网络图中使用文本标签

边和节点可能都有名字,但默认时这些名字可能没有被当作标签,为了设置标签,可以给vertex.label参数传递一个命名向量,如下所示:

1
2
3
4
5
6
7
8
9
10
library(igraph)
library(gcookbook)
m <- madmen[1:nrow(madmen) %% 2==1,]
# copy madem and delete ever number row
g<- graph.data.frame(m,directed = FALSE)
V(g)$name
# output name of nodes

mark

绘图:

1
2
3
4
5
6
plot(g,layout=layout.fruchterman.reingold,
vertex.size = 4, # shrink node
vertex.label = V(g)$name,
vertex.label.cex=0.8,
vertex.label.dist=0.4,# separate lable and nodes
vertex.label.color="black")

mark

另一种能得到相同效果的方法是修改绘图对象,这样就不用给plot()函数传递对数了,此时,可以使用V()$xxx <-来代替vertex.xxx参数传递值,例如下面的代码可以得到和前面一样的输出:

1
2
3
4
5
6
7
8
V(g)$size <- 4
V(g)$label <- V(g)$name
V(g)$label.cex <- 0.8
V(g)$label.dist <- 0.4
V(g)$label.color <- "black"
g$layout <- layout.fruchterman.reingold
plot(g)

mark

设置边的属性

使用E()函数或者给edge.xxx参数传递相应值,如下所示:

1
2
3
4
5
6
7
8
9
10
# check edge
E(g)
# Name edge "M"
E(g)[c(2,11,19)]$label <- "M"
# Set all color of edges is grey, others are red
E(g)$color <- "grey70"
E(g)[c(2,11,19)]$color <- "red"
plot(g)

mark

热图

使用geom_tile()或者geom_raster(),并将一个连续变量映射到fill上,使用Presidents数据集,如下所示:

1
2
3
4
5
6
7
8
9
10
> presidents
Qtr1 Qtr2 Qtr3 Qtr4
1945 NA 87 82 75
1946 63 50 43 32
1947 35 60 54 55
1948 36 39 NA NA
1949 69 57 57 51
1950 45 37 46 39
1951 36 24 32 23
... ...

这是一个时间序列格式,首选将它转换为ggplot()可用的数据框格式,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
pres_rating <- data.frame(
rating = as.numeric(presidents),
year = as.numeric(floor(time(presidents))),
quarter =as.numeric(cycle(presidents))
)
head(pres_rating)
# rating year quarter
# 1 NA 1945 1
# 2 87 1945 2
# 3 82 1945 3
# 4 75 1945 4
# 5 63 1946 1
# 6 50 1946 2

现在使用geom_tile()geom_raster()来绘制,如下所示:

1
2
p <- ggplot(pres_rating,aes(x=year,y=quarter,fill=rating))
p+geom_tile()

mark

或者使用geom_raster(),如下所示:

1
p+geom_raster()

mark

上图中的灰色区域是缺失值。

为了更有效地表达信息,可以自定义热图的外观,现在我们倒转y轴,这样顺序就是从上到下了,并且在x轴上每隔4年添加一个坐标刻度值来表示一个总统任期,此外,再更换颜色标度,使用scale_fill_gradient2()调色板,该调色板可以设置一个中点和两个端点的色彩值,如下所示:

1
2
3
4
p + geom_tile() +
scale_x_continuous(breaks=seq(1940,1976,by=4)) +
scale_y_reverse() +
scale_fill_gradient2(midpoint=50, mid="grey70", limits=c(0,100))

mark